/*
* $file: udpflood.c
* $func: flood udp packet, just for testing network performance
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <net/if.h>

#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>

#define BUFF_SIZE		2048	/*data buffer size */
#define MAX_THREAD		50		/* max threads */

struct sockaddr_in remote_addr;
unsigned char data_buff[BUFF_SIZE];
static void* send_thread(void *arg);

int thread_count = 1;
int send_interval = 1000*1000;
int loop_send = 0;
int data_len = 256;

void usage()
{
	printf("Usage:\n");
	printf("\t-i ip       dst ip\n");
	printf("\t-p port     dst port\n");
	printf("\t-d string   data\n");
	printf("\t-l number   data length\n");
	printf("\t-o loop send\n");
	printf("\t-t therad count\n");
	printf("\t-e inverval\n\n");

}


int main (int argc, char *argv[])
{
	int i;
	char c;
	char cmd;

	memset(data_buff, 'X', sizeof(data_buff));
	memset (&remote_addr, 0, sizeof (struct sockaddr_in));

	if(argc < 3) {
		usage();
		exit(-1);
	}

	while((c = getopt(argc,argv, "i:p:d:l:ot:e:"))!= -1)
	{
		switch(c)
		{
			case 'i':
				printf(" -i %s\n", optarg);
				remote_addr.sin_addr.s_addr = inet_addr(optarg);
				break;
			case 'p':
				printf(" -p %s\n", optarg);
				remote_addr.sin_port = htons(atol(optarg));
				break;
			case 'd':
				printf(" -d %s\n", optarg);
				memcpy(data_buff, optarg, strlen(optarg));
				data_len = strlen(optarg);
				break;
			case 'l':
				printf(" -l %s\n", optarg);
				data_len = atoi(optarg);
				if(data_len > BUFF_SIZE) {
					data_len = BUFF_SIZE;
				}
				break;
			case 'o':
				printf(" -o\n");
				loop_send = 1;
				break;
			case 't':
				printf(" -t %s\n", optarg);
				thread_count = atoi(optarg);
				if(thread_count > 50) {
					thread_count = 50;
				}
				break;
			case 'e':
				printf(" -e %s\n", optarg);
				send_interval = atoi(optarg);
				if(send_interval < 50) {
					send_interval = 50;
				}
				break;
			default:
				usage();
				return 0;
				break;
		}
	}

    printf("now creating %d sending thread...\n", thread_count);
    for (i = 0; i < thread_count; i++) {
		pthread_t ntid;
        int status = pthread_create(&ntid, NULL, send_thread, NULL);
        if (status) {
            printf("create thread failed!reason:%d\n", status);
            exit(-1);
        }
		pthread_detach(ntid);

		usleep(100*1000);
    }
    printf("all %d sending threads created!\n", i);

    printf("now threads are sending data to host, press q to exit\n");

    while (cmd != 'q') {
        sleep(1);
        cmd = getchar();
    }

    return (0);
}

static void *send_thread(void *arg)
{
    int sock;
    int len = 0; /*sending bytes in once time */

	/* create socket */
    if ((sock = socket (AF_INET, SOCK_DGRAM, 0)) < 0) {
        perror("socket():");
        exit (-1);
    }

    do{
        /* data sending process */
        len = sendto(sock, data_buff, data_len, 0, (struct sockaddr *)&remote_addr, sizeof(struct sockaddr_in));
        if (len <= 0) {
            perror("sendto():");

			printf("sock : %d\n", sock);
			printf("data_buff : %s\n", data_buff);
			printf("data_len : %d\n", data_len);
			printf("remote_ip : %s\n", inet_ntoa(remote_addr.sin_addr));
			printf("remote_port : %d\n", ntohs(remote_addr.sin_port));
			printf("sockaddr len : %ld\n", sizeof(struct sockaddr_in));

            pthread_exit(NULL);
        } else {
//			printf("Thread %ld send one package %d ok\n", pthread_self(), len);
		}

		if(send_interval>0) {
			usleep(send_interval);
		}
    }while(loop_send);

	printf ("send to remote end...\n");

	return NULL;
}

